#ifndef MODBUSDEVICE_H
#define MODBUSDEVICE_H

/**
 * @copyright Copyright (c) 2025 
 * CSG Digital Grid Technology (Guangdong) Co., Ltd.
 * @author zhouyan
 * @brief modbus规约设备管理
*/
#include "dx_type.h"
#include "sys_inc.h"
#include "tools/m_mutex.h"

#include "idevice.h"
#include "reginfo.h"

class IPhyLink;
class ModbusTransfer;
class ModbusDevice : public IDevice
{
public:

    struct ModbusReg {
        uint8_t  func_code;
        uint16_t addr;
        uint16_t reg_num;
        uint8_t  data_pos;
        uint8_t  return_size;

        bool calcDataPosAndReturnSize(bool tcp);
        bool compare(ModbusReg* l, ModbusReg* r);
    };
    struct YKRegInfo
    {
        std::string  name;
        uint16_t     on;
        uint16_t     off;
        DXType       type;
        double       rate;
        double       b;
        bool         val;
    };
    typedef std::list<YKRegInfo> YKRegInfos;

    struct RegGroup {
        ModbusReg       modbus;
        RegInfos        infos;
    };

    typedef std::list<RegGroup*> RegGroups;

    struct YKRegGroup {
        ModbusReg               modbus;
        YKRegInfos              infos;
        std::list<std::string>  linkRegs;
        RegBase*                syncReg;
    };
    typedef std::list<YKRegGroup> YKRegGroups;

public:
    ModbusDevice(uint16_t bay_id, uint16_t dev_id, IPhyLink *phy_dev);
    ~ModbusDevice();

    virtual int genDevice(cJSON *root, cJSON *model_root, const char *model_name,
                           uint64_t dev_addr, cJSON *arr_params);

    virtual bool isActived(void) const;

    virtual const RegBase * getYX(const char *reg_name);
    virtual bool hasYX(const char *reg_name);
    virtual bool setPreset(
                        const char*         app,
                        const char*         dev,
                        const char*         name,
                        const char*         reg_name,
                        const char*         uid,
                        const char*         type,
                        const int32_t       cmd,
                        const int32_t       action,
                        const int32_t       mode,
                        const int32_t       timeout);
    virtual bool setYK(
                    const char*         app,
                    const char*         dev,
                    const char*         name,
                    const char*         reg_name,
                    const char*         uid,
                    const char*         type,
                    const int32_t       cmd,
                    const int32_t       action,
                    const int32_t       mode,
                    const int32_t       timeout);

    virtual bool setYK(const char *reg_name, uint32_t status);
    virtual bool hasYK(const char *reg_name);

    virtual const RegBase *  getYC(const char *reg_name);
    virtual bool hasYC(const char *reg_name);

    virtual bool getTime(DateTime_t &tm);
    virtual bool setTime(const DateTime_t &tm);

    virtual int updateGatherTime(void *group);
    virtual int updateReg(/*uint32_t tm*/);
    virtual int actions();

    virtual void dumpYX(void);
    virtual void dumpYC(void);
    virtual void clearRegs();

    virtual void getAllRegs(Datas &regs) const;
    virtual void getYX(Datas &datas, bool force);
    virtual void getYC(Datas &datas, bool force);

protected:
    int updateRegGroup(RegGroup &group, MMutex &mtx);
    int _setYK(const char *reg_name, uint32_t status);
    int parseYKRegInfo(cJSON *root, YKRegGroup & group);
    int parseRegGroup(cJSON *root, RegGroup &group, cJSON *arr_params);
    int parseYKRegGroup(cJSON *root, YKRegGroup &group, cJSON *arr_params);
    int parseRegGroups(cJSON *root, const char *block_name, RegGroups &reg_infos, cJSON *arr_params);
    int parseYKRegGroups(cJSON *root, const char *block_name, YKRegGroups &reg_infos, cJSON *arr_params);
    bool parseModbusParam(cJSON *root, ModbusReg & modbus, cJSON *arr_params);

    int sendCmdAndRecv(const ModbusReg &reg, uint8_t *recv_buf);

    std::vector<std::string> parseStringObject(cJSON *js);

    void dumpData(const RegGroups &regs);
    RegBase * findReg(RegGroups &regs, const std::string &name);

protected:
    bool                actived_;
    uint8_t             slave_addr_;
    std::string         model_name_;
    RegGroups           yx_regs_;
    RegGroups           yc_regs_;
    YKRegGroups         yk_regs_;

    uint8_t*            recv_buf_;
    MMutex              yc_mtx_;
    MMutex              yx_mtx_;
    MMutex              yk_mtx_;

    ModbusTransfer*     transfer_;

    uint16_t            order_;
};

#endif // MODBUSDEVICE_H
